#region Copyright Notice
// 
// 
//  
//  Copyright (c) 2009-2011 Anindya Chatterjee
//  
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//  
//      http://www.apache.org/licenses/LICENSE-2.0
//  
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// 
// 
#endregion
using System;
using System.Collections.Generic;

namespace AbstractClass
{
    /// <summary>
    /// Represents a menu user interface in a console based application.
    /// </summary>
    public class ConsoleMenu
    {
        private readonly Dictionary<int, MenuItem> _menuItems = new Dictionary<int, MenuItem>();
        private int _negativeCount;
        private int _positiveCount;

        /// <summary>
        /// Initializes a new instance of the <see cref="ConsoleMenu"/> class.
        /// </summary>
        public ConsoleMenu()
        {
            IsCompact = false;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ConsoleMenu"/> class.
        /// </summary>
        /// <param name="isCompact">if set to <c>true</c> the menu will be compactly formatted.</param>
        public ConsoleMenu(bool isCompact)
        {
            IsCompact = isCompact;
        }

        /// <summary>
        /// Gets or sets a value indicating whether the menu is compactly formatted..
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is compactly formatted; otherwise, <c>false</c>.
        /// </value>
        public bool IsCompact { get; set; }

        /// <summary>
        /// Adds a menu label and its corresponding command.
        /// </summary>
        /// <param name="text">The menu label.</param>
        /// <param name="menuCommand">The menu command.</param>
        public void Add(string text, Action menuCommand)
        {
            _menuItems.Add(++_positiveCount, new MenuItem(text, menuCommand));
        }

        /// <summary>
        /// Adds a menu separator.
        /// </summary>
        public void AddSeparator()
        {
            _menuItems.Add(--_negativeCount, null);
        }

        /// <summary>
        /// Adds a menu separator.
        /// </summary>
        /// <param name="heading">The label for the separator.</param>
        public void AddSeparator(string heading)
        {
            _menuItems.Add(--_negativeCount, new MenuItem(heading, null));
        }

        /// <summary>
        /// Displays the menu in console window.
        /// </summary>
        public void Show()
        {
            Console.WriteLine(LanguageResource.ConsoleMenuShowSelectAnItemByItsNumber);
            Console.WriteLine();
            int i = 0;

            foreach (var menuItem in _menuItems)
            {
                if (menuItem.Key > 0)
                {
                    Console.WriteLine(@" [{0}] {1}", i + 1, menuItem.Value.Text);
                    i++;
                }
                else
                {
                    if (!IsCompact) Console.WriteLine();
                    string heading = menuItem.Value != null ? menuItem.Value.Text : "";
                    Console.WriteLine(@"     -----------" + heading + @"-----------");
                    if (!IsCompact) Console.WriteLine();
                }
            }

            int choosen;
            Int32.TryParse(Console.ReadLine(), out choosen);

            if (choosen > _positiveCount || choosen < 1)
            {
                Console.WriteLine(LanguageResource.ConsoleMenuShowInvalidOption);
            }
            else
            {
                MenuItem mi = _menuItems[choosen];
                if (mi != null)
                {
                    Action mc = mi.MenuCallback;
                    mc.DynamicInvoke();
                }
            }
        }

        #region Nested type: MenuItem

        private class MenuItem
        {
            public readonly Action MenuCallback;
            public readonly string Text;

            public MenuItem(string text, Action mc)
            {
                MenuCallback = mc;
                Text = text;
            }
        }

        #endregion
    }
}